﻿using System;
using System.Collections.Generic;
using System.Data;
using TfsReports.Web.Models;

namespace TfsReports.Web.Helpers
{
    /// <summary>
    /// TfsWarehouse
    /// </summary>
    public static class TfsWarehouse
    {
        #region Churns

        /// <summary>
        /// Gets all churns.
        /// </summary>
        /// <returns></returns>
        internal static List<Churn> GetAllChurns()
        {
            List<Churn> churns = Cache.Get<List<Churn>>("Churns");
            if (churns == null)
                churns = GetChurnsFromDb();
            else if (churns.Count > 0)
            {
                churns.Sort((c1, c2) => c2.Date.CompareTo(c1.Date));
                if (churns[0].Date < DateTime.Now.AddMinutes(-10))
                    churns = GetChurnsFromDb();
            }
            Cache.Add("Churns", churns);
            return GetDistinctChangeSets(churns);
        }

        /// <summary>
        /// Gets the churns from db.
        /// </summary>
        /// <returns></returns>
        private static List<Churn> GetChurnsFromDb()
        {
            string query = "SELECT "
                          + "[Code Churn].__Id ChurnId, "
                          + "[Work Item].System_Id WorkItemId, "
                          + "[Work Item].System_Title WorkItemTitle, "
                          + "[Changeset].[Changeset Id] ChangesetId, "
                          + "[Changeset].Changeset ChangesetTitle, "
                          + "[Person].__Id PersonId, "
                          + "[Person].Person PersonTitle, "
                          + "[Code Churn].__LastUpdatedTime Date, "
                          + "[Code Churn].[Lines Added] LinesAdded, "
                          + "[Code Churn].[Lines Modified] LinesModified, "
                          + "[Code Churn].[Lines Deleted] LinesDeleted "
                          + "FROM [Work Item] "
                          + "JOIN [Work Item Changeset] on [Work Item].__Id = [Work Item Changeset].[Work Item] "
                          + "JOIN [Changeset] on [Work Item Changeset].Changeset = [Changeset].__Id "
                          + "JOIN [Code Churn] on [Changeset].__Id = [Code Churn].Changeset "
                          + "JOIN [Person] on [Code Churn].[Checked in By] = [Person].__Id";

            List<Churn> churns = Cache.Get<List<Churn>>("Churns");
            if (churns != null && churns.Count > 0)
            {
                churns.Sort((c1, c2) => c2.Date.CompareTo(c1.Date));
                query += string.Format(" WHERE [Code Churn].__LastUpdatedTime > CAST('{0}' AS datetime)", churns[0].Date.ToString("yyyy-MM-dd HH:mm:ss"));
            }
            else
                churns = new List<Churn>();
            using (IDataReader dataReader = Data.GetDataReader("TfsWarehouse", query, null))
                while (dataReader.Read())
                    churns.Add(new Churn(dataReader));
            return churns;
        }

        /// <summary>
        /// Gets the distinct change sets.
        /// </summary>
        /// <param name="churns">The churns.</param>
        /// <returns></returns>
        private static List<Churn> GetDistinctChangeSets(List<Churn> churns)
        {
            List<int> changesetIds = new List<int>();
            List<Churn> distinct = new List<Churn>();
            churns.ForEach(c =>
            {
                if (!changesetIds.Contains(c.Changeset.Id))
                {
                    changesetIds.Add(c.Changeset.Id);
                    distinct.Add(c);
                }
            });
            return distinct;
        }

        #endregion

        #region Builds

        /// <summary>
        /// Gets all builds.
        /// </summary>
        /// <returns></returns>
        public static List<Build> GetAllBuilds()
        {
            List<Build> builds = Cache.Get<List<Build>>("Builds");
            if (builds == null)
                builds = GetBuildsFromDb();
            else if (builds.Count > 0)
            {
                builds.Sort((b1, b2) => b2.Start.CompareTo(b1.Start));
                if (builds[0].Start < DateTime.Now.AddMinutes(-10))
                    builds = GetBuildsFromDb();
            }
            Cache.Add("Builds", builds);
            return builds;
        }

        /// <summary>
        /// Gets the builds from db.
        /// </summary>
        /// <returns></returns>
        private static List<Build> GetBuildsFromDb()
        {
            string query = "SELECT "
                          + "[Build].__Id BuildId, "
                          + "[Build].Build Title, "
                          + "[Build].[Build Type] Definition, "
                          + "[Build].[Drop Location] DropLocation, "
                          + "[Build].[Build Start Time] Start, "
                          + "[Build Details].[Build Duration] Duration, "
                          + "[Build Status].__Id BuildStatusId, "
                          + "[Build Status].[Build Status] BuildStatus "
                          + "FROM [Build] "
                          + "JOIN [Build Details] ON [Build Details].Build = [Build].__Id "
                          + "JOIN [Build Status] ON [Build Status].__Id = [Build Details].[Build Status]";

            List<Build> builds = Cache.Get<List<Build>>("Builds");
            if (builds != null && builds.Count > 0)
            {
                builds.Sort((b1, b2) => b2.Start.CompareTo(b1.Start));
                query += string.Format(" WHERE [Build].[Build Start Time] > CAST('{0}' AS datetime)", builds[0].Start.ToString("yyyy-MM-dd HH:mm:ss"));
            }
            else
                builds = new List<Build>();
            using (IDataReader dataReader = Data.GetDataReader("TfsWarehouse", query, null))
            {
                while (dataReader.Read())
                    builds.Add(new Build(dataReader));
            }
            return builds;
        }

        /// <summary>
        /// Gets the builds for changeset.
        /// </summary>
        /// <param name="changesetId">The changeset id.</param>
        /// <returns></returns>
        public static List<Build> GetBuildsForChangeset(int changesetId)
        {
            List<Build> allBuilds = GetAllBuilds();
            List<Build> buildsForChangeset = new List<Build>();
            GetAllBuildChangesets().FindAll(bc => bc.ChangesetId == changesetId).ForEach(bc => buildsForChangeset.Add(GetBuildFast(bc.BuildId, allBuilds)));
            return buildsForChangeset;
        }

        /// <summary>
        /// Gets the changesets for build.
        /// </summary>
        /// <param name="buildId">The build id.</param>
        /// <returns></returns>
        public static List<Changeset> GetChangesetsForBuild(int buildId)
        {
            List<Changeset> allChangesets = GetAllChangesets();
            List<Changeset> changesetsForBuild = new List<Changeset>();
            GetAllBuildChangesets().FindAll(bc => bc.BuildId == buildId).ForEach(bc => changesetsForBuild.Add(GetChangesetFast(bc.ChangesetId, allChangesets)));
            return changesetsForBuild;
        }

        /// <summary>
        /// Gets the build.
        /// </summary>
        /// <param name="buildId">The build id.</param>
        /// <returns></returns>
        public static Build GetBuild(int buildId)
        {
            return GetBuildFast(buildId, GetAllBuilds());
        }

        /// <summary>
        /// Gets the build fast.
        /// </summary>
        /// <param name="buildId">The build id.</param>
        /// <param name="builds">The builds.</param>
        /// <returns></returns>
        public static Build GetBuildFast(int buildId, List<Build> builds)
        {
            return builds.Find(b => b.Id == buildId);
        }

        /// <summary>
        /// Gets the change set.
        /// </summary>
        /// <param name="changesetId">The changeset id.</param>
        /// <returns></returns>
        public static Changeset GetChangeset(int changesetId)
        {
            return GetChangesetFast(changesetId, GetAllChangesets());
        }

        /// <summary>
        /// Gets the changeset fast.
        /// </summary>
        /// <param name="changesetId">The changeset id.</param>
        /// <param name="changesets">The changesets.</param>
        /// <returns></returns>
        public static Changeset GetChangesetFast(int changesetId, List<Changeset> changesets)
        {
            return changesets.Find(c => c.Id == changesetId);
        }

        /// <summary>
        /// Gets all build changesets.
        /// </summary>
        /// <returns></returns>
        public static List<BuildChangeset> GetAllBuildChangesets()
        {
            List<BuildChangeset> buildChangesets = Cache.Get<List<BuildChangeset>>("BuildChangesets");
            if (buildChangesets == null)
                buildChangesets = GetBuildChangesetsFromDb();
            else if (buildChangesets.Count > 0)
            {
                buildChangesets.Sort((bc1, bc2) => bc2.ChangesetId.CompareTo(bc1.ChangesetId));
                List<Churn> churns = GetAllChurns();
                churns.Sort((c1, c2)=>c2.Changeset.Id.CompareTo(c1.Changeset.Id));
                if (buildChangesets[0].ChangesetId < churns[0].Changeset.Id)
                    buildChangesets = GetBuildChangesetsFromDb();
            }
            Cache.Add("BuildChangesets", buildChangesets);
            return buildChangesets;
        }

        /// <summary>
        /// Gets the build changesets from db.
        /// </summary>
        /// <returns></returns>
        private static List<BuildChangeset> GetBuildChangesetsFromDb()
        {
            string query = "SELECT "
                          + "[Build Changeset].Changeset ChangesetId, "
                          + "[Build Changeset].Build BuildId "
                          + "FROM [Build Changeset]";

            List<BuildChangeset> buildChangesets = Cache.Get<List<BuildChangeset>>("BuildChangesets");
            if (buildChangesets != null && buildChangesets.Count > 0)
            {
                buildChangesets.Sort((bc1, bc2) => bc2.ChangesetId.CompareTo(bc1.ChangesetId));
                query += string.Format(" WHERE [Build Changeset].Changeset > {0}", buildChangesets[0].ChangesetId);
            }
            else
                buildChangesets = new List<BuildChangeset>();
            using (IDataReader dataReader = Data.GetDataReader("TfsWarehouse", query, null))
                while (dataReader.Read())
                    buildChangesets.Add(new BuildChangeset(dataReader));
            return buildChangesets;
        }

        #endregion

        #region Changesets

        /// <summary>
        /// Gets all changesets.
        /// </summary>
        /// <returns></returns>
        public static List<Changeset> GetAllChangesets()
        {
            List<Changeset> changesets = Cache.Get<List<Changeset>>("Changesets");
            if (changesets == null)
                changesets = GetChangesetsFromDb();
            else if (changesets.Count > 0)
            {
                changesets.Sort((c1, c2) => c2.Id.CompareTo(c1.Id));
                List<Churn> churns = GetAllChurns();
                churns.Sort((c1, c2) => c2.Changeset.Id.CompareTo(c1.Changeset.Id));
                if (changesets[0].Id < churns[0].Changeset.Id)
                    changesets = GetChangesetsFromDb();
            }
            Cache.Add("Changesets", changesets);
            return changesets;
        }

        /// <summary>
        /// Gets the changesets from db.
        /// </summary>
        /// <returns></returns>
        private static List<Changeset> GetChangesetsFromDb()
        {
            string query = "SELECT "
                          + "[Changeset].__Id ChangesetId, "
                          + "[Changeset].Changeset ChangesetTitle "
                          + "FROM [Changeset]";

            List<Changeset> changesets = Cache.Get<List<Changeset>>("Changesets");
            if (changesets != null && changesets.Count > 0)
            {
                changesets.Sort((bc1, bc2) => bc2.Id.CompareTo(bc1.Id));
                query += string.Format(" WHERE [Changeset].__Id > {0}", changesets[0].Id);
            }
            else
                changesets = new List<Changeset>();
            using (IDataReader dataReader = Data.GetDataReader("TfsWarehouse", query, null))
                while (dataReader.Read())
                    changesets.Add(new Changeset(dataReader));
            return changesets;
        }

        #endregion
    }
}
